package im.yangqiang.android.ui.widget.chart;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.RectF;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.View;

import java.util.ArrayList;

import im.yangqiang.android.ui.R;

/**
 * 扇形统计图
 * Created by Carlton on 2016/6/24.
 */
public class SectorChartView extends View
{
    private static final boolean DEBUG = false;
    /**
     * 最小大小,单位是dp
     */
    private final int MIN_SIZE = 200;
    /**
     * 元数据
     */
    private ArrayList<Entry> mDatum = new ArrayList<>();
    /**
     * 画笔
     */
    private Paint mPaint = new Paint();
    /**
     * 文字画笔
     */
    private TextPaint mFontPaint = new TextPaint();
    /**
     * 开始绘制的角度
     */
    private float mStartAngel = 0;
    /**
     * 绘制过程中，当前扇区的角度
     */
    private float mCurrentAngel = 0;
    /**
     * 文字和扇区的间隔
     */
    private float mFontSpace = 10;
    /**
     * 文字大小
     */
    private float mFontSize = 30;
    /**
     * 圆弧的宽度
     */
    private float mArcWidth = 30;
    /**
     * 中心圆的颜色
     */
    private int mCenterColor = Color.BLACK;
    /**
     * 文字的高度
     */
    private float mTextHeight = 0;
    /**
     * 文字是否跟随圆弧
     */
    private boolean mIsFontArc = false;

    public SectorChartView(Context context)
    {
        this(context, null, 0);

    }

    public SectorChartView(Context context, AttributeSet attrs)
    {
        this(context, attrs, 0);
    }

    public SectorChartView(Context context, AttributeSet attrs, int defStyleAttr)
    {
        super(context, attrs, defStyleAttr);
        if (android.os.Build.VERSION.SDK_INT >= 11)
        {
            setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        }
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.SectorChartView, defStyleAttr, 0);
        mStartAngel = typedArray.getFloat(R.styleable.SectorChartView_start_angel, 0);
        mFontSpace = typedArray.getDimension(R.styleable.SectorChartView_font_space, 10);
        mFontSize = typedArray.getDimensionPixelSize(R.styleable.SectorChartView_font_size, 30);
        mArcWidth = typedArray.getDimension(R.styleable.SectorChartView_arc_width, 30);
        mCenterColor = typedArray.getColor(R.styleable.SectorChartView_center_color, Color.BLACK);
        mIsFontArc = typedArray.getBoolean(R.styleable.SectorChartView_is_font_arc, false);
        typedArray.recycle();

        mPaint.setAntiAlias(true);
        mFontPaint.setAntiAlias(true);
        mFontPaint.setTextSize(mFontSize);
        if (isInEditMode())
        {
            demo();
        }
        mCurrentAngel = mStartAngel;

        entryValueToAngel();
    }

    private void demo()
    {
        mDatum.add(new Entry(Color.RED, 10.0f, "1Hello"));
        mDatum.add(new Entry(Color.BLUE, 20.0f, "2Hello"));
        mDatum.add(new Entry(Color.GREEN, 40.0f, "3Hello"));
        mDatum.add(new Entry(Color.GRAY, 15.0f, "4Hello"));
        mDatum.add(new Entry(Color.YELLOW, 15.0f, "5Hello"));
    }

    public void setData(ArrayList<Entry> data)
    {
        mDatum = data;
        entryValueToAngel();
    }

    /**
     * 绘制的Rect
     */
    private RectF mDrawOval = new RectF();
    private Path mTempPath = new Path();

    @Override
    protected void onDraw(Canvas canvas)
    {
        super.onDraw(canvas);
        canvas.save();
        mCurrentAngel = mStartAngel;
        final float left = getPaddingLeft() + mFontSpace + mTextHeight;
        final float top = getPaddingTop() + mFontSpace + mTextHeight;
        final float right = getMeasuredWidth() - getPaddingRight() - mFontSpace - mTextHeight;
        final float bottom = getMeasuredHeight() - getPaddingBottom() - mFontSpace - mTextHeight;
        mDrawOval.set(left, top, right, bottom);
        final RectF rawRect = mDrawOval;
        final RectF fontRect = new RectF(rawRect.left - mFontSpace, rawRect.top - mFontSpace, rawRect.right + mFontSpace, rawRect.bottom + mFontSpace);
        for (Entry entry : mDatum)
        {
            mPaint.setStyle(Paint.Style.FILL);
            mPaint.setColor(entry.getColor());
            canvas.drawArc(rawRect, mCurrentAngel, entry.getAngel(), true, mPaint);
            // 添加路径用于绘制文字
            mTempPath.reset();
            mTempPath.addArc(fontRect, mCurrentAngel, entry.getAngel());
            mCurrentAngel += entry.getAngel();
            // 绘制文字
            mPaint.setColor(entry.getColor());
            final float textWidth = getTextWidth(mFontPaint, entry.getText());
            float hOffset = ((float) getArcLength(entry.getAngel(), fontRect.width() / 2) / 2) - textWidth / 2;
            if (mIsFontArc)
            {
                canvas.drawTextOnPath(entry.getText(), mTempPath, hOffset, 0, mFontPaint);
            } else
            {
                PointF point = getArcPoint(fontRect.centerX(), fontRect.centerY(), fontRect.width() / 2, -mCurrentAngel + entry.getAngel() / 2);
                float fontX = point.x - textWidth / 2;
                float fontY = point.y;
                // 在圆心的左边则减去字体的一半
                fontX += ((fontX <= rawRect.centerX()) ? -1 : 1) * textWidth / 2;
                // 在圆心的上边则减去字体的一半
                fontY += ((fontY <= rawRect.centerY()) ? -1 : 1) * mTextHeight / 2;
                canvas.drawText(entry.getText(), fontX, fontY, mFontPaint);
            }
            if (DEBUG)
            {
                mPaint.setStyle(Paint.Style.STROKE);
                canvas.drawPath(mTempPath, mPaint);
            }
        }
        // 绘制中心的圆心
        mPaint.setColor(mCenterColor);
        mPaint.setStyle(Paint.Style.FILL);
        float arcWidth = rawRect.width() / 2 - mArcWidth;
        float arcHeight = rawRect.height() / 2 - mArcWidth;
        mDrawOval.set(rawRect.centerX() - arcWidth, rawRect.centerY() - arcHeight, rawRect.centerX() + arcWidth, rawRect.centerY() + arcHeight);
        canvas.drawOval(mDrawOval, mPaint);
        canvas.restore();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        int paddingLeft = getPaddingLeft();
        int paddingTop = getPaddingTop();
        int paddingRight = getPaddingRight();
        int paddingBottom = getPaddingBottom();

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int paddingH = paddingLeft + paddingRight;
        int paddingV = paddingTop + paddingBottom;

        int desired = (int) (MIN_SIZE * getResources().getDisplayMetrics().density + 0.5f);

        if (widthMode == MeasureSpec.EXACTLY)
        {
            widthSize = MeasureSpec.getSize(widthMeasureSpec);
        } else if (widthMode == MeasureSpec.AT_MOST)
        {
            widthSize = Math.min(desired, widthSize - paddingH);
        }

        if (heightMode == MeasureSpec.EXACTLY)
        {
            heightSize = MeasureSpec.getSize(heightMeasureSpec);
        } else if (heightMode == MeasureSpec.AT_MOST)
        {
            heightSize = Math.min(desired, heightSize - paddingV);
        }

        final int size = Math.min(widthSize, heightSize);
        setMeasuredDimension(size, size);

        mTextHeight = getTextHeight(mFontPaint);
    }

    /**
     * 计算圆弧上的坐标点
     * x2 = x + r * cos(角度值 * PI / 180)
     * y2 = y - r * sin(角度值 * PI / 180)
     *
     * @param x     中心x
     * @param y     中心y
     * @param r     半径
     * @param angel 角度
     * @return
     */
    private PointF getArcPoint(float x, float y, float r, float angel)
    {

        double x1 = x + (r * Math.cos(angel * Math.PI / 180));
        double y1 = y - (r * Math.sin(angel * Math.PI / 180));
        return new PointF((float) x1, (float) y1);
    }

    /**
     * 返回字体高度
     *
     * @param paint
     * @return
     */
    private float getTextHeight(TextPaint paint)
    {
        return paint.descent() - paint.ascent();
    }

    /**
     * 获取文字的宽度
     *
     * @param paint
     * @param text
     * @return
     */
    private float getTextWidth(TextPaint paint, String text)
    {
        return paint.measureText(text);
    }

    /**
     * 获取弧长
     *
     * @param angel 角度
     * @param r     半径
     * @return
     */
    private double getArcLength(float angel, float r)
    {
        return angel * Math.PI * r / 180;
    }

    /**
     * 元数据的百分比转换成角度
     *
     * @return
     */
    private void entryValueToAngel()
    {
        /*
        *   剩余的角度
        */
        float surplusAngel = 360;
        for (Entry entry : mDatum)
        {
            float angel = percentToAngel(entry.getValue());
            if (angel >= surplusAngel)
            {
                entry.setAngel(surplusAngel);
                break;
            } else if (surplusAngel - angel <= 0)
            {
                entry.setAngel(surplusAngel);
                break;
            } else
            {
                entry.setAngel(angel);
                surplusAngel -= angel;
            }
        }
    }

    /**
     * 百分比转换成角度
     *
     * @return
     */
    private float percentToAngel(float value)
    {
        return 360 * value / 100;
    }

    /**
     * 元数据
     */
    public static class Entry
    {
        /**
         * 颜色
         */
        private int color;
        /**
         * 百分比数量
         */
        private float value;
        /**
         * 角度
         */
        private float angel = 0;
        /**
         * 文字
         */
        private String text;

        public Entry(int color, float value)
        {
            this.color = color;
            this.value = value;
        }

        public Entry(int color, float value, String text)
        {
            this.color = color;
            this.value = value;
            this.text = text;
        }

        public int getColor()
        {
            return color;
        }

        public void setColor(int color)
        {
            this.color = color;
        }

        public float getValue()
        {
            return value;
        }

        public void setValue(float value)
        {
            this.value = value;
        }

        public float getAngel()
        {
            return angel;
        }

        public void setAngel(float angel)
        {
            this.angel = angel;
        }

        public String getText()
        {
            return text;
        }

        public void setText(String text)
        {
            this.text = text;
        }
    }
}
